package mount

import (
	"bytes"
	"context"
	"fmt"
	"go.uber.org/zap"
	"golang.org/x/text/encoding/simplifiedchinese"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"
	"virus-proxy/internal/logger"
)

var _ DiskOperator = (*WindowsDiskOperator)(nil)

type WindowsDiskOperator struct {
	Username string
	Password string
}

func NewWindowsDisk(username, password string) *WindowsDiskOperator {
	return &WindowsDiskOperator{Username: username, Password: password}
}

func (o *WindowsDiskOperator) FSMount(fsPath, username, passwd string) (err error) {
	var mountPoint string
	var i int
	for i = MountNum - 1; i >= MinMountNum; i-- {
		if MountSliceIns.Drives[i] == "" {
			mountPoint = string('A'+rune(i)) + ":"
			break
		}
	}
	if mountPoint == "" {
		return fmt.Errorf("no available mount point")
	}
	// 将fsPath的"/"转变为"\"
	newFsPath := strings.ReplaceAll(fsPath, "/", "\\")
	// Windows环境下，使用net use挂载共享
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	var cmd *exec.Cmd
	if username != "" {
		username = bytes.NewBufferString("/user:" + username).String()
		cmd = exec.CommandContext(ctx, "net", "use", mountPoint, newFsPath, username, passwd)
	} else {
		cmd = exec.CommandContext(ctx, "net", "use", mountPoint, newFsPath)
	}
	out, err := cmd.CombinedOutput()
	if err != nil {
		output, err := simplifiedchinese.GB18030.NewDecoder().String(string(out)) //转换字符集，解决UTF-8乱码
		if err != nil {
			logger.LogError("TransCode failed. ", zap.String("fsPath", fsPath), zap.String("mountPoint", mountPoint), zap.Error(err))
			return err
		}
		logger.LogError("Mounting failed. ", zap.String("fsPath", fsPath), zap.String("mountPoint", mountPoint), zap.Error(err))
		return fmt.Errorf("%s", output)
	}
	logger.LogInfo("Filesystem mounted.", zap.String("fsPath", fsPath), zap.String("mountPoint", mountPoint))
	// 更新MountArray
	MountSliceIns.Mutex.Lock()
	MountSliceIns.Drives[i] = fsPath
	MountSliceIns.Mutex.Unlock()
	return nil
}
func (o *WindowsDiskOperator) UnMountFS(fsPath, clientIp string) (err error) {
	fsPath = bytes.NewBufferString("//" + clientIp + fsPath).String()
	var unMountPoint string
	var i int
	for i = MountNum - 1; i >= MinMountNum; i-- {
		if strings.EqualFold(MountSliceIns.Drives[i], fsPath) {
			unMountPoint = string('A'+rune(i)) + ":"
			break
		}
	}
	// Windows环境下，使用net use卸载共享
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, "net", "use", "/d", unMountPoint)
	out, err := cmd.CombinedOutput()
	if err != nil {
		output, err := simplifiedchinese.GB18030.NewDecoder().String(string(out)) //转换字符集，解决UTF-8乱码
		if err != nil {
			logger.LogError("Transcode failed. ", zap.Error(err))
			return err
		}
		logger.LogError("UnMounting failed. ", zap.Error(err))
		return fmt.Errorf("%s", output)
	}
	logger.LogInfo("Filesystem unmounted", zap.String("mountPoint", unMountPoint))
	// 更新MountArray
	MountSliceIns.Mutex.Lock()
	MountSliceIns.Drives[i] = ""
	MountSliceIns.Mutex.Unlock()
	return nil

}

func (o *WindowsDiskOperator) CheckMountHealth(fsPath, clientIp string) (err error) {
	fsPath = bytes.NewBufferString("//" + clientIp + fsPath).String()
	MountSliceIns.Mutex.RLock()
	defer MountSliceIns.Mutex.RUnlock()
	_, err = os.ReadDir(fsPath)
	return
}

func (o *WindowsDiskOperator) IsMounted(fsPath string) (mounted bool, err error) {
	fsPath = bytes.NewBufferString("//" + fsPath).String()
	for _, val := range MountSliceIns.Drives {
		if strings.EqualFold(val, fsPath) {
			return true, nil
		}
	}
	return false, err

}
func (o *WindowsDiskOperator) ListMount() (bytes []byte, err error) {
	// Windows环境下,使用net use查看共享文件系统是否已经挂载
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, "net", "use")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return nil, err
	}
	return output, nil
}

func (o *WindowsDiskOperator) ParseDf(bytes []byte) {
	MountSliceIns.Drives = make([]string, MountNum)
	// 查询本机挂载点利用正则表达式切分后,初始化MountArray
	lines := strings.Split(string(bytes), "\r\n")
	//mountRegex := regexp.MustCompile(`^\s*\w+\s+([A-Z]:)\s+(\\\\[^\s]+)`)
	mountRegex := regexp.MustCompile(`([A-Z]:)\s+(\\\\[^\s]+)`)
	for _, line := range lines {
		matches := mountRegex.FindStringSubmatch(line)
		if len(matches) < 3 {
			continue
		}
		driverLetter := matches[1]
		remotePath := matches[2]

		index := int(driverLetter[0] - 'A')
		MountSliceIns.Drives[index] = remotePath
		if index < MinMountNum || index >= MountNum {
			continue
		}
		// 将remotePath中的'\'改为'/'
		remotePath = strings.ReplaceAll(remotePath, "\\", "/")
		MountSliceIns.Drives[index] = remotePath
	}
}
